package module;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.ice.db.AdapterFactory;
import org.ice.registry.IRegistry;
import org.ice.registry.RegistryFactory;
import org.icy.core.setup.RequirementVerification;
import org.icy.core.setup.VerificationResult;
import org.icy.core.setup.manipulate.ConfigManipulate;
import org.icy.core.setup.verification.DatabaseVerification;
import org.icy.modules.IcyModule;

public class InstallModule extends IcyModule {

	private int step;

	public void indexTask() {
		IRegistry reg = RegistryFactory.getRegistry();
		String status = (String) reg.get("icy.app.status");
		step = 1;
		if (status.equals("initial")) {
			String license = getParam("license");
			if (license != null)
				step++;

			String passed = getParam("passed");
			if (passed != null)
				step = 3;
		} else if (status.equals("db")) {
			step = 4;
		}

		runStep(step);
		setRequestAttribute("step", step);
		setRequestAttribute("stepView", moduleUrl + "/step" + step + ".jsp");
	}

	private void runStep(int step) {
		try {
			Method method = getClass().getMethod("step" + step);
			method.invoke(this);
		} catch (Exception ex) {
		}
	}

	public void step2() {
		RequirementVerification rv = new RequirementVerification();
		ArrayList<VerificationResult> list = rv
				.checkRequirements(RequirementVerification.MOD_ALL);
		setRequestAttribute("list", list);
		boolean failed = false;
		boolean next = true;
		for (VerificationResult rs : list) {
			if (!rs.result) {
				next = false;
				if (rs.required) {
					failed = true;
				}
			}
		}
		setRequestAttribute("failed", failed);

		if (next) {
			nextStep();
		}
	}

	public void step3() {
		DatabaseVerification dbv = new DatabaseVerification();
		ArrayList<VerificationResult> dbs = dbv.getSupportedDatabases();
		ArrayList<String> errors = new ArrayList<String>();
		setRequestAttribute("dbs", dbs);
		setRequestAttribute("errors", errors);
		setRequestAttribute("dbHost", "localhost");

		if (getParam("submitted") != null) {
			String dbType = getParam("db_type");
			String dbName = getParam("db_name");
			String dbUserName = getParam("db_username");
			String dbPassword = getParam("db_passwd");
			String dbHost = getParam("db_host");
			String dbPort = getParam("db_port");

			if (dbType == null || dbType.isEmpty())
				errors.add("You must specify the database type");
			if (dbName == null || dbName.isEmpty())
				errors.add("You must specify the database name");
			if (dbUserName == null || dbUserName.isEmpty())
				errors.add("You must specify the database username");
			if (dbHost == null || dbHost.isEmpty())
				errors.add("You must specify the database host");

			String adapter = dbv.getSupportedAdapter(dbType);

			// test database connection
			if (errors.isEmpty()) {
				try {
					AdapterFactory.setupAdapter(adapter, dbHost, dbPort,
							dbUserName, dbPassword, dbName);
				} catch (Exception ex) {
					errors.add("Failed to establish a connection to the database server: "
							+ ex.toString());
				}
			}

			// save the settings in the configuration file
			if (errors.isEmpty()) {
				Map<String, String> settings = new HashMap<String, String>();
				settings.put("ice.db.host", dbHost);
				settings.put("ice.db.port", dbPort);
				settings.put("ice.db.name", dbName);
				settings.put("ice.db.username", dbUserName);
				settings.put("ice.db.password", dbPassword);
				settings.put("ice.db.adapter", adapter);
				settings.put("icy.app.status", "db");
				
				ConfigManipulate cm = new ConfigManipulate(settings);
				try {
					cm.manipulate(true);
					nextStep();
				} catch (Exception ex) {
					errors.add("Unable to save the settings, please try again. Error message: ");
				}
			}

			if (!errors.isEmpty()) {
				// preserve the db settings
				setRequestAttribute("dbType", dbType);
				setRequestAttribute("dbName", dbName);
				setRequestAttribute("dbUserName", dbUserName);
				setRequestAttribute("dbHost", dbHost);
				setRequestAttribute("dbPassword", dbPassword);
				setRequestAttribute("dbPort", dbPort);
			}
		}
	}

	private void nextStep() {
		step++;
		runStep(step);
	}

	@Override
	public String getModuleName() {
		return "install";
	}
}